package api

import (
	"context"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"

	"github.com/go-redis/redis/v8"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"mxshop_api/user-web/forms"
	"mxshop_api/user-web/global"
	"mxshop_api/user-web/global/reponse"
	middlewares2 "mxshop_api/user-web/middlewares"
	"mxshop_api/user-web/models"
	"mxshop_api/user-web/proto"
	"mxshop_api/user-web/utils"
	"net/http"
	"strconv"
	"strings"
	"time"
)
func removeTopStruct(fields map[string]string) map[string]string{
	rsp :=map[string]string{}
	for field,err :=range fields{
		rsp[field[strings.Index(field,".")+1:]] =err
	}
	return rsp
}
func handleValidatorError(c *gin.Context,err error){
	errs,ok :=err.(validator.ValidationErrors)
	if !ok{
		c.JSON(http.StatusBadRequest,gin.H{
			"error":err.Error(),
		})
	}
	c.JSON(http.StatusBadRequest,gin.H{
		"error":removeTopStruct(errs.Translate(global.Trans)),
	})
}
func HandleGrpcErrorToHttp(err error, c *gin.Context) {
	if err != nil {
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				c.JSON(http.StatusNotFound, gin.H{
					"msg": e.Message(),
				})
			case codes.Internal:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "内部出错",
				})
			case codes.InvalidArgument:
				c.JSON(http.StatusBadRequest, gin.H{
					"msg": "传入参数出错",
				})
			default:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "其他出错",
				})
			}
		}
	}
}

func GetUserList(ctx *gin.Context) {

	pn := ctx.DefaultQuery("pn","0")
	pnInt,_ :=strconv.Atoi(pn)
	pSize := ctx.DefaultQuery("psize","10")
	pSizeInt,_ :=strconv.Atoi(pSize)

	rsp, err := global.UserSrvClient.GetUserList(context.Background(), &proto.PageInfo{
		Pn:    uint32(pnInt),
		PSize:  uint32(pSizeInt),
	})
	if err != nil {
		zap.S().Info(err.Error())
		zap.S().Errorw("[GetUserList] 查询用户列表失败")
		HandleGrpcErrorToHttp(err, ctx)
		return
	}
	result := make([]interface{}, 0)
	for _, value := range rsp.Data {
		user := reponse.UserResponse{
			Id:       value.Id,
			NickName: value.NickName,
			Birthday: reponse.JsonTime(time.Unix(int64(value.BirthDay), 0)),
			Gender:   value.Gender,
			Mobile:   value.Mobile,
		}
		result = append(result, user)
	}
	ctx.JSON(http.StatusOK, result)
}

func PassWordLogin(c *gin.Context) {
	var pawForm forms.PassWordLoginForm
	if err :=c.ShouldBind(&pawForm);err !=nil{
		handleValidatorError(c,err)
		return
	}
	if !store.Verify(pawForm.CaptchaId,pawForm.Captcha,false){
		c.JSON(http.StatusBadRequest,gin.H{
			"captcha":"验证码错误",
		})
		return
	}
	//拨号

	rsp ,err :=global.UserSrvClient.GetUserByMobile(context.Background(),&proto.MobileRequest{
		Mobile: pawForm.Mobile,
	})
	if err !=nil{
		if e,ok :=status.FromError(err);ok{
			switch e.Code() {
			case codes.NotFound:
				c.JSON(http.StatusBadRequest,map[string]string{
				"mobile":"用户不存在",
				})
			default:
				c.JSON(http.StatusInternalServerError,map[string]string{
				"mobile":"登录失败",
				})
			}
			return
		}
	}else {
		if passRsp,passErr :=global.UserSrvClient.CheckPassWord(context.Background(),&proto.PasswordCheckInfo{
			Password: pawForm.PassWord,
			EncryptedPassword: rsp.PassWord,
		}); passErr !=nil{
			c.JSON(http.StatusInternalServerError,map[string]string{
				"password":"内部grpc出错",
			})
		}else {
			if passRsp.Success{
				//生成token
				j := middlewares2.NewJWT()
				claims :=models.CustomClaims{
					ID:             uint(rsp.Id),
					NickName:       rsp.NickName,
					AuthorityId:    uint(rsp.Role),
					StandardClaims: jwt.StandardClaims{
						NotBefore: time.Now().Unix(), //生成的生效时间
						ExpiresAt: time.Now().Unix()+60*60*24*30,
						Issuer: "imooc",
					},
				}
				token,err :=j.CreateToken(claims)
				if err != nil {
					c.JSON(http.StatusInternalServerError,gin.H{
						"msg":"生成的token失败",
					})
					return
				}
				c.JSON(http.StatusOK,gin.H{
					"id":rsp.Id,
					"nick_name":rsp.NickName,
					"token":token,
					"expired_at":(time.Now().Unix()+60*60*24*30)*1000,
				})
				c.JSON(http.StatusOK,map[string]string{
					"password":"登录成功",
				})
			}else {
				c.JSON(http.StatusOK,map[string]string{
					"password":"密码错误",
				})
			}

		}

	}
}



func SendSms(c *gin.Context){
	sendSmsForm :=forms.SendSmsForm{}
	if err:=c.ShouldBind(&sendSmsForm);err!=nil{
		handleValidatorError(c,err)
		return
	}
	smsCode :=utils.GenerateSmsCode(6)
	rdb := redis.NewClient(&redis.Options{
		Addr:fmt.Sprintf("%s:%d",global.ServerConfig.RedisInfo.Host,global.ServerConfig.RedisInfo.Port),
	})

	rdb.Set(context.Background(),sendSmsForm.Mobile,smsCode,time.Duration(global.ServerConfig.RedisInfo.Expire)*time.Second)

	c.JSON(http.StatusOK,gin.H{
		"msg":"发送成功",
	})
}


func Register(c *gin.Context){
	registerForm :=forms.RegisterForm{}
	if err :=c.ShouldBind(&registerForm);err !=nil{
		handleValidatorError(c,err)
		return
	}
	rdb :=redis.NewClient(&redis.Options{
		Addr:fmt.Sprintf("%s:%d",global.ServerConfig.RedisInfo.Host,global.ServerConfig.RedisInfo.Port),
	})
	value, err :=rdb.Get(context.Background(),registerForm.Mobile).Result()
	if err == redis.Nil{
		c.JSON(http.StatusBadRequest,gin.H{
			"code":"验证码错误",
		})
		return
	}else {
		if value !=registerForm.Code{
			c.JSON(http.StatusBadRequest,gin.H{
				"code":"验证码错误",
			})
			return
		}
	}

	user ,err :=global.UserSrvClient.CreateUser(context.Background(),&proto.CreateUserInfo{
		NickName: registerForm.Mobile,
		Mobile: registerForm.Mobile,
		PassWord: registerForm.PassWord,
	})
	if err !=nil{
		zap.S().Errorf("[Register] 查询 【新建用户失败】失败: %s",err.Error())
		HandleGrpcErrorToHttp(err,c)
		return
	}
	j :=middlewares2.NewJWT()
	claims := models.CustomClaims{
		ID: uint(user.Id),
		NickName: user.NickName,
		AuthorityId: uint(user.Role),
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix(),
			ExpiresAt: time.Now().Unix()+60*60*24*30,
			Issuer: "CHX",
		},
	}
	token,err :=j.CreateToken(claims)
	if err != nil {
		c.JSON(http.StatusInternalServerError,gin.H{
			"msg":"生成的token出错",
		})
		return
	}
	c.JSON(http.StatusOK,gin.H{
		"id":user.Id,
		"nick_name":user.NickName,
		"token":token,
		"expired_at": (time.Now().Unix() + 60*60*24*30)*1000,
	})
}